/**
 * 图文混排组件
 */

// 动态用法
// let ti = new TextWithImage;
// ti.text = s;

// 编辑器用法：见pnl_main_task_item
// 给TextWithImage加一个skin，skin里放一个id:label of eui.Label，设置label的属性即可！
// imagesize 图片大小
// singleline 单行

// 例子：@white#Bblue#s(48)###Ggre#ben#Rred#c(001)
// #uclick100#nhe##l##lo#s(32)#e(001)#n#lworld!#s(60)#p(110)world#s(40)#t(1003)#k(11)
// @#s(200)#i(0110_png)
// @#s(200)#t(1003)
// @#s(100)#t(1003)
// @bbb#bbbb
// @获得了#s(80)#t(1003)
// #是标识符
// #A-#Z颜色值，设定在utils.ts中
// #b bold #u underline #l 斜体 #n 清除 #r换行
// #s(size) 字体大小 #z(color) 颜色
// #c(click) click的文字点击会调用函数 TextEvent.ts onTextEvent
// 动画 #e(ani) 表情 #p(player) #a(任意动画)
// 图片 icon #k(skill) #t(item) #h(char) #i(任意图片)

const cImagechar = '　'; // 全角的空格！

// bulnsc已经用到了
const charofmark = 'rszciktehpafo'; // line(r) size(s) color(z) click(c) image(i) skill(k) item(t) emote(e) char(h) player(p) ani(a)

// 希望点击超链接不关闭dlg，而点中其他地方关闭，所以只能重写这个函数！
// eslint-disable-next-line dot-notation
egret.TextField.prototype['onTapHandler'] = function westOnTapTextField(e: egret.TouchEvent): void {
	if (this.$TextField[24 /* type */] === egret.TextFieldType.INPUT) {
		return;
	}
	const ele = egret.TextFieldUtils.$getTextElement(this, e.localX, e.localY);
	if (ele == null) {
		return;
	}
	const { style } = ele;
	if (style && style.href) {
		if (style.href.match(/^event:/)) {
			const type = style.href.match(/^event:/)[0];
			egret.TextEvent.dispatchTextEvent(
				this,
				egret.TextEvent.LINK,
				style.href.substring(type.length),
			);
		} else {
			// eslint-disable-next-line no-restricted-globals
			open(style.href, style.target || '_blank');
		}
		e.stopPropagation(); // 取消后面的capture或者冒泡
		e.stopImmediatePropagation(); // 后续的listener不继续执行了
	}
};

function copyLabelProperty(des: egret.TextField, src: egret.TextField): void {
	des.fontFamily = src.fontFamily;
	des.size = src.size;
	des.bold = src.bold;
	des.italic = src.italic;

	des.lineSpacing = src.lineSpacing;
	des.textColor = src.textColor;

	des.border = src.border;
	des.borderColor = src.borderColor;
	des.stroke = src.stroke;
	des.strokeColor = src.strokeColor;

	des.background = src.background;
	des.backgroundColor = src.backgroundColor;

	// des.wordWrap = src.wordWrap;
	des.wordWrap = true;
}

const spaceChar = '\u0020';
/**
 * @param labelWidth 皮肤中标签宽度
 * @param labelHeight 皮肤中标签高度
 * @param fontSize 字体大小
 * @param text 需转化的文本
 * '|'表示换列
 * 将横向从左至右顺序的文本转换为纵向从左至右的字符串。
 * 调用示例：getVerticalText(208, 200, 20, '朝辞白帝彩云间，|千里江陵一日还。|两岸猿声啼不住，|轻舟已过万重山。')
 */
function getVerticalText(
	labelWidth: number,
	labelHeight: number,
	fontSize: number,
	text: string,
): string {
	if (!text) {
		return '';
	}
	const row = Math.floor(labelHeight / fontSize);
	const column = Math.ceil(labelWidth / row);
	if (row <= 0) {
		return '';
	}
	const arr: Array<Array<string>> = [];
	for (let i = 0; i < row; i++) {
		arr.push([]);
	}
	for (let i = 0; i < arr.length; i++) {
		for (let j = 0; j < column; j++) {
			arr[i].push(spaceChar);
		}
	}
	let deltaX = 0;
	let deltaY = 0;
	for (let index = 0; index < text.length; index++) {
		if (text[index] === '|') {
			deltaY++;
			deltaX = 0;
			continue;
		}
		const y = Math.floor(deltaX / row) + deltaY;
		const x = deltaX % row;
		arr[x][y] = text[index] || spaceChar;
		deltaX++;
	}
	const str: string[] = [];
	for (const r of arr) {
		for (const c of r) {
			str.push(c);
		}
	}
	// console.log('重组后：', arr);
	return str.join('');
}

/**
 * @param labelWidth 皮肤中标签宽度
 * @param labelHeight 皮肤中标签高度
 * @param fontSize 字体大小
 * @param text 需转化的文本
 * '|'表示换列
 * 将横向从左至右顺序的文本转换为纵向从右至左的字符串。
 * 调用示例：getVerticalReverseText(208, 200, 20, '朝辞白帝彩云间，|千里江陵一日还。|两岸猿声啼不住，|轻舟已过万重山。')
 */
function getVerticalReverseText(
	labelWidth: number,
	labelHeight: number,
	fontSize: number,
	text: string,
): string {
	if (!text) {
		return '';
	}
	const row = Math.floor(labelHeight / fontSize);
	const column = Math.ceil(labelWidth / row);
	if (row <= 0) {
		return '';
	}
	const arr: Array<Array<string>> = [];
	for (let i = 0; i < row; i++) {
		arr.push([]);
	}
	for (let i = 0; i < arr.length; i++) {
		for (let j = 0; j < column; j++) {
			arr[i].push(spaceChar);
		}
	}
	let deltaX = 0;
	let deltaY = 0;
	for (let index = 0; index < text.length; index++) {
		if (text[index] === '|') {
			deltaY++;
			deltaX = 0;
			continue;
		}
		const y = column - 1 - Math.floor(deltaX / row) - deltaY;
		const x = deltaX % row;
		arr[x][y] = text[index] || spaceChar;
		deltaX++;
	}
	const str: string[] = [];
	for (const r of arr) {
		for (const c of r) {
			str.push(c);
		}
		str.push('\n');
	}
	console.log('重组后：', arr);
	return str.join('');
}

// default.thm.json.
// "TextWithImage": "resource/skins/misc/tiSkin.exml",

function findTiNextPos(s:string, pos:number):number {
	const ch2 = s[pos + 1];
	if (charofmark.indexOf(ch2) >= 0) {
		const leftmark = s[pos + 2];
		const rightmark = s.indexOf(')', pos + 3);
		let bad = false;
		if (leftmark !== '(' || rightmark < 0) {
			bad = true;
			return pos + 1;
		}
		return rightmark + 1;
	}
	return pos + 2;
}

class TextWithImage extends eui.Component {
	// public templet: egret.TextField
	// constructor() {
	// super();
	// this.skinName = 'tiSkin';
	// }

	label: eui.Label;

	private group: eui.Group;

	private groupEmote: eui.Group;

	private curColor: number;

	private curSize: number;

	private underline = false;

	private italic = false;

	private bold = false;

	private href = '';

	private oriWidth = 0;

	private oriHeight = 0;

	private tf: egret.TextField;

	input: string = '';

	public get text(): string {
		return this.input;
	}

	public set text(v: string) {
		this.input = v;
		// 如果创建成功！
		if (this.group) {
			this.createRichtext(v);
		}
	}

	format = false;

	setText(v:string, format:boolean) {
		this.input = v;
		this.format = format;
		if (this.group) {
			this.createRichtext(v, format);
		}
	}

	public setStyle(lb: eui.Label): void {
		copyLabelProperty(this.label, lb);
	}

	override childrenCreated(): void {
		super.childrenCreated();

		if (!this.group) {
			this.group = new eui.Group();
			this.addChild(this.group);
			this.group.touchChildren = false;
			this.group.touchEnabled = false;
		}
		if (!this.groupEmote) {
			this.groupEmote = new eui.Group();
			this.addChild(this.groupEmote);
			this.group.touchChildren = false;
			this.group.touchEnabled = false;
		}

		if (this.label) {
			this.label.visible = false;
			this.removeChild(this.label);
		} else {
			this.label = new eui.Label();
		}

		if (this.text) {
			this.createRichtext(this.text, this.format);
		}
	}

	pushArray(a: Array<egret.ITextElement>, ss: string): void {
		const s = ss.replaceAll('##', '#');
		const obj: egret.ITextElement = { text: s };
		const style: egret.ITextStyle = {};
		if (this.curColor !== this.label.textColor) {
			style.textColor = this.curColor;
		}
		if (this.curSize !== this.label.size) {
			style.size = this.curSize;
		}
		if (this.italic) {
			style.italic = true;
			// style["alpha"] = 0.5;
		}
		if (this.bold) {
			style.stroke = 1;
			style.strokeColor = this.curColor;
		}
		if (this.underline) {
			style.underline = true;
			// style["alpha"] = 0.5;
		}
		if (this.href) {
			style.href = `event:${this.href}`;
		}
		obj.style = style;
		a.push(obj);
	}

	findKeyPos(s: string, start = 0): number {
		const pos = s.indexOf('#', start);
		if (pos < 0) {
			return pos;
		}
		if (s[pos + 1] === '#') { // ##表示#号
			return this.findKeyPos(s, pos + 2);
		}
		return pos;
	}

	addArray(a: Array<egret.ITextElement>, s: string, start: number): void {
		// console.log("add_array",s)
		// let pos = s.indexOf("#");
		const pos = this.findKeyPos(s, start);

		if (pos < 0) {
			this.pushArray(a, s);
		} else {
			const left = s.substring(0, pos);
			if (left.length > 0) {
				this.pushArray(a, left);
			}

			const ch2 = s[pos + 1];
			let rightstart = pos + 2;
			const startfind = 0;

			if (ch2 >= 'A' && ch2 <= 'Z') {
				this.curColor = miscUtils.getFormatColor(ch2);
			} else if (ch2 === 'n') {
				this.clear();
			} else if (ch2 === 'u') {
				this.underline = true;
			} else if (ch2 === 'b') {
				this.bold = true;
			} else if (ch2 === 'l') {
				this.italic = true;
			} else if (ch2 === 'r') {
				this.pushArray(a, '\n');
			} else if (charofmark.indexOf(ch2) >= 0) {
				// find ()
				const leftmark = s[pos + 2];
				const rightmark = s.indexOf(')', pos + 3);

				let bad = false;
				if (leftmark !== '(' || rightmark < 0) {
					bad = true;
				}

				if (!bad) {
					egret.assert(rightmark > 0);
					const param = s.substring(pos + 3, rightmark);

					if (ch2 === 'c') {
						this.href = param;
					} else if (ch2 === 's') {
						const curSize = Number(param);
						if (curSize > 24 && curSize < 240) {
							this.curSize = curSize;
						}
					} else if (ch2 === 'z') {
						const cr = parseInt(param, 16);
						if (cr >= 0 && cr <= 0xffffff) {
							this.curColor = cr;
						}
					} else {
						const old = this.curSize;
						if (this.imagesize !== 0) {
							this.curSize = this.imagesize;
						}
						if (ch2 === 'e') { // emote
							this.curSize = this.label.size;
						} // ori size!
						this.pushArray(a, cImagechar);
						this.images.push([ch2, param, this.curSize * 2]);
						if (this.imagesize !== 0 || ch2 === 'e') {
							this.curSize = old;
						}
					}

					rightstart = rightmark + 1;
				} else {
					// rightstart = 0;
					// startfind = pos+1;
				}
			} else {
				// rightstart = 0;
				// startfind = pos+1;
			}
			const right = s.substring(rightstart);
			this.addArray(a, right, startfind);
		}
	}

	// [type,image,cursize]
	private images: [string, string, number][] = [];

	// rich text like white#Bblue#Ggreen#Rred#c(l00)click100#nhello#i(100)world!
	// #大写字母代表颜色
	// #c(eventid)代表点击事件
	// #n代表结束
	// #i(100)代表img
	clear(): void {
		this.curColor = this.label.textColor || 0;
		this.curSize = this.label.size;
		this.bold = this.label.bold;
		this.italic = this.label.italic;

		this.underline = false;
		this.href = '';

		this.width = this.oriWidth;
		this.height = this.oriHeight;
		// this.label.textColor = this.textColor;
		// this.label.size = this.size;
		// this.label.bold = this.initbold;
	}

	resetWidth(width:number) {
		this.oriWidth = width;
		this.width = width;
	}

	clearAll(): void {
		this.clear();
		this.images = [];
	}

	singleline = false;

	imagesize = 0;

	trace() {
		const lb = this.textField;
		let lattr = lb.$getLinesArr();
		if (!lattr) {
			lattr = lb.$getLinesArr();
		}
		if (!lattr) {
			return;
		}

		let line = 0;
		let height = 0;
		for (const item of lattr) {
			console.log('line', line, height, { len: item.elements.length, w: item.width, h: item.height });
			for (const element of item.elements) {
				// console.log(x, height, element.text, element.width);
				// x += element.width;
			}
			line++;
			height += item.height + lb.lineSpacing;
		}
	}

	private createRichtext(s: string, format = false): void {
		if (format) {
			s = miscUtils.formatGameString(s);
		}
		// console.log('createRichtext', s);

		if (this.oriWidth === 0) {
			this.oriWidth = this.width;
			this.oriHeight = this.height;
			// console.log('ti.oriSize', this.width, this.height);
		}
		// this.removeChildren();
		this.group.removeChildren();
		this.groupEmote.removeChildren();

		this.clearAll();

		if (typeof s !== 'string') {
			s = '';
		}
		// eslint-disable-next-line no-irregular-whitespace
		s = s.replace(/　/g, '  '); // 全角空格替换为2个半角空格！

		const a : Array<egret.ITextElement> = [];
		this.addArray(a, s, 0);

		// const lb = this.label; 复用this.label会出错！应该是底层的bug！
		const lb = new egret.TextField();
		// lb.lineSpacing
		copyLabelProperty(lb, this.label);
		if (this.textField) {
			this.removeChild(this.textField);
		}
		this.textField = lb;
		this.addChildAt(lb, 0);

		// 10000够了，不能用100000这样更大的数，会导致egret的bug！
		lb.width = this.singleline ? 10000 : this.width;
		lb.textFlow = a;

		lb.touchEnabled = true;
		lb.addEventListener(egret.TextEvent.LINK, this.onLink, this);
		// TextField.addEventListener(egret.TouchEvent.TOUCH_TAP,this.onTapText,this);

		let index = 0;
		let height = 0;

		// TextField.prototype.$getLinesArr = function () {
		//     var values = this.$TextField;
		//     if (egret.nativeRender && values[38 /* textLinesChangedForNativeRender */]) {
		//         egret_native.updateNativeRender();
		//         values[38 /* textLinesChangedForNativeRender */] = false;
		//         return;
		//     }
		//     else {
		//         return this.$getLinesArr2();
		//     }
		// };

		// egret nativeEngine  bug 导致必须获得2次!
		let lattr = lb.$getLinesArr();
		if (!lattr) {
			lattr = lb.$getLinesArr();
		}
		if (lattr) {
			for (const item of lattr) {
				let { x, y } = lb;
				for (const element of item.elements) {
					// console.log(x, height, element.text, element.width);
					if (element.text === cImagechar) {
						const image = this.images[index++];
						const imgobj = CreateImageInText(
							image[0],
							image[1],
							image[2],
							x,
							height,
							element.width,
							item.height,
							this.label.size,
						);
						if (image[0] === 'e') {
							this.groupEmote.addChild(imgobj);
						} else {
							this.group.addChild(imgobj);
						}
					}
					x += element.width;
				}
				height += item.height + lb.lineSpacing;
			}
		}

		this.height = lb.textHeight;
		// if (singleline) { this.width = lb.textWidth; }
		this.width = lb.textWidth;
		this.right = undefined;
		this.bottom = undefined;
		// console.log('ti.createRichtext',this.width,this.height,lb.textWidth,lb.textHeight,);
	}

	// onTapText(ev:egret.TouchEvent){}

	onLink(evt: egret.TextEvent): void {
		WestTextEvent.ins().onTextEvent(evt.text);
	}

	textField: egret.TextField;

	Ani = false;

	stopAni = true;

	inAni():boolean {
		return this.Ani;
	}

	async showTextOneByOne(s:string, wait:number) {
		let sign = '';

		const sign1 = '......';
		const sign2 = '...';

		if (s.endsWith(sign1)) {
			sign = sign1;
		} else if (s.endsWith(sign2)) {
			sign = sign2;
		}

		if (sign) {
			s = s.substr(0, s.length - sign.length);
			// havesign = true;
		}

		this.Ani = true;

		this.stopAni = false;
		for (let i = 1; i <= s.length; i++) {
			if (s[i - 1] === '#') {
				i = findTiNextPos(s, i - 1);
			}
			const text = s.substring(0, i);
			this.createRichtext(text);
			await waitMs(wait);
			if (this.stopAni) {
				this.createRichtext(s);
				break;
			}
		}

		this.stopAni = true;

		if (sign) {
			for (let i = 0; i <= sign.length; i++)	{
				this.createRichtext(s + sign.substr(0, i));
				await waitMs(wait * 5);
			}
		}

		this.Ani = false;
	}

	stopShow() {
		this.stopAni = true;
	}

	// private _xAlign: number;

	// public get xAlign(): number {
	// 	return this._xAlign;
	// }

	// public set xAlign(v: number) {
	// 	this._xAlign = v;
	// 	this.updateAlign();
	// }

	// private _yAlign: number;

	// public get yAlign(): number {
	// 	return this._yAlign;
	// }

	// public set yAlign(v: number) {
	// 	this._yAlign = v;
	// 	this.updateAlign();
	// }

	// // not normally align,并且是单行有效！
	// updateAlign(): void {
	// 	if (!this.singleline) {
	// 		return;
	// 	}
	// 	const x = this.xAlign;
	// 	const y = this.yAlign;
	// 	const lb = this.textField;
	// 	if (x === 0) {
	// 		lb.x = (this.oriWidth - this.width) / 2;
	// 	} else if (x === -1) {
	// 		lb.x = 0;
	// 	} else if (x === 1) {
	// 		lb.x = this.oriWidth - this.width;
	// 	}
	// 	if (y === 0) {
	// 		lb.y = (this.oriHeight - this.height) / 2;
	// 	} else if (y === -1) {
	// 		lb.y = 0;
	// 	} else if (y === 1) {
	// 		// lb.y = -(this.oriHeight - this.height);
	// 		lb.y = 0;
	// 	}
	// 	this.group.x = lb.x;
	// 	this.group.y = lb.y;
	// 	this.groupEmote.x = lb.x;
	// 	this.groupEmote.y = lb.y;
	// }
}
